#include "Game.h"
#include "Model3D.h"
#include "PhysicShape.h"
#include "PhysicManager.h"
#include "Character.h"
#include "BasicEffect.h"
#include "TexturesManager.h"
#include "Skybox.h"
#include "ModelsManager.h"
#include "ExplosionsManager.h"
#include "Keyboard.h"
#include "ShadowRender.h"
#include "DepthEffect.h"
#include "XnaMath.h"
Game*  Game::mInstance = NULL;

Game::Game()
{

}

Game::~Game()
{

}

Game* Game::Instance()
{
	if(mInstance == NULL)
	{
		mInstance = new Game();
	}
	return mInstance;
}

bool Game::Initialize()
{
	mDeviceContext = CDirect3D::Instance()->GetDeviceContext();
	mDevice = CDirect3D::Instance()->GetDevice();

	PhysicManager::Instance()->Initialize();

	mShader = new BasicEffect();
	mShader->Initialize();

	mShadowRender = new ShadowRender();
	mShadowRender->Initialize();

	TexturesManager::Instance()->AddTexture("SHADOW",mShadowRender->GetTexture());


	ModelsManager::Instance()->Initialize();

	mPhysicShapes = new PhysicShape[5];

	mPhysicShapes[0].Initialize("Contents\\Models\\Road_001.obj", BvhTriangle);
	mPhysicShapes[1].Initialize("Contents\\Models\\Road_cross_001.obj", BvhTriangle);
	mPhysicShapes[2].Initialize("Contents\\Models\\Road_cross_002.obj", BvhTriangle);
	mPhysicShapes[3].Initialize("Contents\\Models\\Build_001.obj", BvhTriangle);
	mPhysicShapes[4].Initialize("Contents\\Models\\cube.obj", Triangle);

	mMainRenderItemManager = new RenderItemManager();
	mTransparentRenderItemManager = new RenderItemManager();
	mDecalRenderItemManager = new RenderItemManager();

	mCamera = new Camera();
	mCamera->SetPosition(0.0f, 2.0f, -20.0f);

	mScene = new Scene();
	mScene->Initialize();

	mSkybox = new Skybox();
	mSkybox->Initialize();

	mExplosionsManager = ExplosionsManager::Instance();
	mExplosionsManager->Initialize();


	mLightOrientation = XMFLOAT3(1.0,-1.0,0.5);
	

	posiZ = 0;
	mLastExplode = 0;
	return true;
}

void Game::Uninit()
{

}

void Game::Update(int pElapsedTime)
{
	PhysicManager::Instance()->Update(pElapsedTime);
	mScene->Update(pElapsedTime);
	mExplosionsManager->Update(pElapsedTime);

	if(Keyboard::Instance()->IsKeyDown(84))
	{
		XMStoreFloat3(&mLightOrientation, XMVector3Transform(XMLoadFloat3(&mLightOrientation), XMMatrixRotationY(0.01)));
	}
	if(Keyboard::Instance()->IsKeyDown(89))
	{
		XMStoreFloat3(&mLightOrientation, XMVector3Transform(XMLoadFloat3(&mLightOrientation), XMMatrixRotationX(0.01)));
	}
	bool startExplose = Keyboard::Instance()->IsKeyDown(46) && mLastExplode > 400;
	bool gravityGun = Keyboard::Instance()->IsKeyDown(65) && mLastExplode > 400;
	if(startExplose || gravityGun)
	{
		mLastExplode = 0;
		rayTestResult result;
		XMFLOAT3 position = mCamera->GetPosition();
		PhysicManager::Instance()->TestRayTest(position, mCamera->GetVectorOrientation(), &result);

		if(startExplose || gravityGun)
		{
			if(result.hit)
			{
				mExplosionsManager->StartExplosion(result.position, result.normal);
			}
			else
			{
				XMFLOAT3 normal = mCamera->GetVectorOrientation();
				XMFLOAT3 explodePosition;
				explodePosition.x = position.x + (normal.x * 50);
				explodePosition.y = position.y + (normal.y * 50);
				explodePosition.z = position.z + (normal.z * 50);
				mExplosionsManager->StartExplosion(explodePosition, normal);
			}
		}	
		if(gravityGun)
		{
			if(result.hit)
			{
				Entity* e = (Entity*)result.userPointer;
				if(e != NULL && !e->IsStatic())
				{
					XMFLOAT3 destination;
					XMStoreFloat3(&destination, XMLoadFloat3(&mCamera->GetVectorOrientation()) * 3 + XMLoadFloat3(&mCamera->GetPosition()));
					
					XMFLOAT3 force;
					force.x = result.position.x;//(destination.x - result.position.x); 
					if(force.x > 0.1) force.x = 0.2;  if(force.x < 0.1) force.x = -0.2; 
					force.y = result.position.y;//(destination.y - result.position.y); 
					if(force.y > 0.1) force.y = 0.2; if(force.y < 0.1) force.y = -0.2; 
					force.z = result.position.z;//(destination.z - result.position.z); 
					if(force.z > 0.1) force.z = 0.2; if(force.z < 0.1) force.z = -0.2; 
					force.x = 0;
					force.y = 10;
					force.z = 0;
					if(Keyboard::Instance()->IsKeyDown(66))
					{
						e->ApplyForce(force, result.position);
					}
					else
					{
						e->ApplyForce(force, result.position);
					}
					
				}
			}
		}
	}
	else
	{
		mLastExplode += pElapsedTime;
	}
}

void Game::PreRender()
{
	mOrigine = GetCamera()->GetPosition();
	mScene->PreRender();
	mMainRenderItemManager->SortIteration(3);
	mTransparentRenderItemManager->SortIterationDesc(3);
	mShader->GetPointsLightsManager()->Update();
}

void Game::Render()
{
	//posiZ -= 0.1f;
	XMFLOAT3 position =  mScene->GetControledCharacter()->getHeadPosition();
	mCamera->SetPosition(position.x, position.y, position.z);
	mCamera->SetRotation(mScene->GetControledCharacter()->getHeadOrienation(),mScene->GetControledCharacter()->getBodyOrienation(),0);
	mCamera->Render();

	mShader->SetEyesPosition(mCamera->GetPosition());

	PreRender();

	mShadowRender->Render();


	CDirect3D::Instance()->BeginScene(0.0f, 0.0f, 0.0f, 1.0f);
	
	mShader->SetShadowTexture(mShadowRender->GetTexture());

	CDirect3D::Instance()->DisableDepthStencil();
	mSkybox->Render();
	CDirect3D::Instance()->EnableDepthStencil();

	mMainRenderItemManager->Render();
	mTransparentRenderItemManager->Render();

	CDirect3D::Instance()->EnableRasterStateForDecal();
	mDecalRenderItemManager->Render();
	CDirect3D::Instance()->DisableRasterStateForDecal();

	mExplosionsManager->Render();

	CDirect3D::Instance()->EndScene();
}

PhysicShape* Game::GetPhysicShape(int pIndex)
{
	return &(mPhysicShapes[pIndex]);
}

Camera* Game::GetCamera()
{
	return mCamera;
}

XMFLOAT3 Game::GetOrigine()
{
	return mOrigine;
}

BasicEffect* Game::GetShader()
{
	return mShader;
}

ShadowRender* Game::GetShadowRender()
{
	return mShadowRender;
}

Texture* Game::GetTexture()
{
	return mTexture;
}

Scene* Game::GetScene()
{
	return mScene;
}

RenderItemManager* Game::GetMainRenderItemManager()
{
	return mMainRenderItemManager;
}

RenderItemManager* Game::GetTransparentRenderItemManager()
{
	return mTransparentRenderItemManager;
}

RenderItemManager* Game::GetDecalRenderItemManager()
{
	return mDecalRenderItemManager;
}

void Game::RenderItemsRaiseAllRemoveFlags()
{
	mMainRenderItemManager->RaiseAllRemoveFlags();
	mTransparentRenderItemManager->RaiseAllRemoveFlags();
	mDecalRenderItemManager->RaiseAllRemoveFlags();
}

void Game::RenderItemsRemoveItemsByFlag()
{
	mMainRenderItemManager->RemoveItemsByFlag();
	mTransparentRenderItemManager->RemoveItemsByFlag();
	mDecalRenderItemManager->RemoveItemsByFlag();
}

XMFLOAT3 Game::GetLightOrientation()
{
	return mLightOrientation;
}

